﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using NativeExcel;
using System.Reflection;
using System.ComponentModel;
using Sinacor.Infra.UI.Common;
using System.Windows;
using PSE.Framework.UI.Resources;
using System.Collections;
using System.IO;
using Sinacor.Infra.Common;
using System.Windows.Data;

namespace Sinacor.Infra.UI.Controls.SmartClient.DataGrid
{
    public partial class SinacorDataGrid
    {
        #region Tratamento de Eventos

        #region ExportExcelCommand

        #region ExportExcelCommand_CanExecute
        private void ExportExcelCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.IsExportableExcel && grid.CanExportExcel();
            e.Handled = true;
        }
        #endregion

        #region ExportExcelCommand_Executed
        private void ExportExcelCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.ExportExcel();
        }
        #endregion

        #endregion

        #region ExportAllExcelCommand

        #region ExportAllExcelCommand_CanExecute
        private void ExportAllExcelCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.IsExportableExcel && grid.CanExportAllExcel();
            e.Handled = true;
        }
        #endregion

        #region ExportAllExcelCommand_Executed
        private void ExportAllExcelCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.ExportAllExcel();
        }
        #endregion

        #endregion

        #endregion

        #region IsExportableExcel
        public static readonly DependencyProperty IsExportableExcelProperty = DependencyProperty.Register("IsExportableExcel", typeof(Boolean), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(true, null, CoerceIsExportableExcel));
        /// <summary>
        /// Indica se o grid suporta exportação para Excel
        /// </summary>
        public Boolean IsExportableExcel
        {
            get { return (Boolean)GetValue(IsExportableExcelProperty); }
            set { SetValue(IsExportableExcelProperty, value); }
        }

        private static object CoerceIsExportableExcel(DependencyObject d, object value)
        {
            SinacorDataGrid grid = d as SinacorDataGrid;
            bool isExportableExcel = false;

            foreach (IDataGridColumn column in grid.Columns)
            {
                if (column.CanUserExportExcel)
                {
                    isExportableExcel = true;
                    break;
                }
            }

            value = isExportableExcel;
            return value;
        }
        #endregion

        #region ExportingExcelEvent
        public static readonly RoutedEvent ExportingExcelEvent = EventManager.RegisterRoutedEvent("ExportingExcel", RoutingStrategy.Bubble, typeof(CancelItemsEventHandler), typeof(SinacorDataGrid));
        /// <summary>
        /// Evento disparado antes da exportação para Excel
        /// </summary>
        public event CancelItemsEventHandler ExportingExcel
        {
            add { AddHandler(ExportingExcelEvent, value); }
            remove { RemoveHandler(ExportingExcelEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ExportingExcel</c>
        /// </summary>
        /// <param name="itemsInfo">Itens sendo exportados</param>
        /// <returns>true se evento não foi cancelado</returns>
        protected virtual bool OnExportingExcel(IList<ItemInfo> itemsInfo)
        {
            CancelItemsEventArgs e = new CancelItemsEventArgs(SinacorDataGrid.ExportingExcelEvent, this, itemsInfo);
            RaiseEvent(e);
            return !e.Cancel;
        }
        #endregion

        #region ExportedExcelEvent
        public static readonly RoutedEvent ExportedExcelEvent = EventManager.RegisterRoutedEvent("ExportedExcel", RoutingStrategy.Bubble, typeof(ItemsEventHandler), typeof(SinacorDataGrid));
        /// <summary>
        /// Evento disparado depois da exportação para Excel
        /// </summary>
        public event ItemsEventHandler ExportedExcel
        {
            add { AddHandler(ExportedExcelEvent, value); }
            remove { RemoveHandler(ExportedExcelEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ExportedExcel</c>
        /// </summary>
        /// <param name="itemsInfo">Itens sendo exportados</param>
        protected virtual void OnExportedExcel(IList<ItemInfo> itemsInfo)
        {
            ItemsEventArgs e = new ItemsEventArgs(SinacorDataGrid.ExportedExcelEvent, this, itemsInfo);
            RaiseEvent(e);
        }
        #endregion

        #region ExportExcel
        /// <summary>
        /// Indica se pode exportar os itens selecionados para Excel
        /// </summary>
        /// <returns>true se puder exportar para Excel, false se não puder</returns>
        protected bool CanExportExcel()
        {
            return /*!this.IsEditing &&*/ this.HasItems() && (this.SelectedItems.Count > 0);
        }

        /// <summary>
        /// Exporta os itens selecionados para Excel
        /// </summary>
        /// <returns>
        /// true se exportou com sucesso, false se a exportação foi cancelada no evento <c>ExportingExcel</c> 
        /// ou se não existem itens selecionados
        /// </returns>
        public bool ExportExcel()
        {
            if (this.CanExportExcel())
            {
                return this.ExportExcel(this.SelectedItems);
            }
            return false;
        }

        /// <summary>
        /// Exporta o item indicado pelo índice para Excel
        /// </summary>
        /// <param name="index">Índice do item</param>
        /// <returns>true se exportou com sucesso, false se a exportação foi cancelada no evento <c>ExportingExcel</c></returns>
        public bool ExportExcel(int index)
        {
            return this.ExportExcel(new int[] { index });
        }

        /// <summary>
        /// Exporta os itens indicados pelos índices para Excel
        /// </summary>
        /// <param name="indexs">Índices dos itens</param>
        /// <returns>true se exportou com sucesso, false se a exportação foi cancelada no evento <c>ExportingExcel</c></returns>
        public bool ExportExcel(int[] indexs)
        {
            if (indexs == null)
                throw new ArgumentNullException("indexs");
            if (indexs.Length == 0)
                throw new ArgumentException("Indexs cannot be empty", "indexs");

            if (/*!this.IsEditing &&*/ this.HasItems())
            {
                object[] items = Array.ConvertAll<int, object>(indexs,
                            delegate(int input)
                            {
                                return this.GetItemsSourceList()[input];
                            });

                return this.ExportExcel(items);
            }

            return false;
        }

        /// <summary>
        /// Exporta os itens para Excel
        /// </summary>
        /// <param name="items">Itens a serem exportados</param>
        /// <returns>true se exportou com sucesso, false se a exportação foi cancelada no evento <c>ExportingExcel</c></returns>
        private bool ExportExcel(IEnumerable items)
        {
            if (items == null)
                throw new ArgumentNullException("items");

            int x = 0;
            int y = 0;
            bool exportedToExcel = false;
            string fileName = "";


            // Alimenta coleção que será disponibilizada nos Eventos ExportingExcel e ExportedExcel
            List<ItemInfo> itemsInfo = FillItemsInfo(items);

            if (this.OnExportingExcel(itemsInfo))
            {
                IWorkbook book = NativeExcel.Factory.CreateWorkbook();
                IWorksheet sheet = book.Worksheets.Add();

                //Classifica coluna pela ordem da exibição para no caso de troca de posição de colunas manualmente.
                IEnumerable<Microsoft.Windows.Controls.DataGridColumn> columns = this.Columns.OrderBy(c => c.DisplayIndex);

                //Preenche o nome das colunas
                foreach (Microsoft.Windows.Controls.DataGridColumn column in columns)
                {
                    //Verifica o parametro AllowExportExcel e Visible para saber se a coluna será exibida ou não
                    if (AllowExportExcel(column))
                    {
                        sheet.Cells[1, y + 1].Value = column.Header;
                        y++;
                    }
                }

                y = 0;

                //Preenche os valores das colunas
                foreach (object item in items)
                {
                    foreach (Microsoft.Windows.Controls.DataGridColumn column in columns)
                    {
                        //Verifica o parametro AllowExportExcel e Visible para saber se a coluna será exibida ou não
                        if (AllowExportExcel(column))
                        {
                            BindingBase excelBinding = ((IDataGridColumn)column).ExcelContentBinding;

                            if (excelBinding != null)
                            {
                                //Formata valores dos membros a serem exibidos
                                sheet.Cells[x + 2, y + 1].Value = FormatProperties(item, excelBinding);
                            }
                            y++;
                        }
                    }
                    y = 0;
                    x++;
                }

                //Salva arquivo gerado
                System.Windows.Forms.SaveFileDialog savDialog = new System.Windows.Forms.SaveFileDialog();
                savDialog.Filter = "*Excel Files(*.xls)\"|*.xls";
                savDialog.AddExtension = true;
                System.Windows.Forms.DialogResult result;
                result = savDialog.ShowDialog();
                string savFile = savDialog.FileName;
                fileName = savFile.Substring(savFile.LastIndexOf("\\") + 1);

                if (result == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        book.SaveAs(savFile);
                        exportedToExcel = true;
                    }
                    catch (IOException ex)
                    {
                        // Loga o erro ao Exportar para o Excel
                        //Session.Session session = Sinacor.Infra.UI.Session.SessionManager.GetInstance().GetCurrentSession();
                        //string user = "";
                        //int companyId = 0;

                        //if (session != null)
                        //{
                        //    user = session.User.LoginName;
                        //    companyId = session.Company.Id;
                        //}

                        //Sinacor.Infra.Common.Logging.Logger.Write(user, Sinacor.Infra.Common.Logging.LogType.Error, "", companyId, "InterfaceLayer", "ExportExcel", ex, "", "Sinacor.Infra.UI.Controls.SinacorDataGrid_Excel: An error occurred while trying to export to excel file.", Sinacor.Infra.Common.Logging.eErrorType.ErroGeral);

                        PSE.Framework.ErrorLogging.LogData logData = Sinacor.Infra.UI.ErrorLogging.ErrorLogger.WriteLog(PSE.Framework.ErrorLogging.LogType.Error, new Exception("An error occurred exporting DataGrid contents to excel file", ex), _extensionData);

                        string message = (string)ResourceProviderManager.GetResourceProvider().TryGetResource("Infra.UI.Message.ArquivoExcelAberto");
                        SinacorMessageBox.ShowError(message, null, logData, Window.GetWindow(this));
                    }
                    catch (Exception ex)
                    {
                        // Loga o erro ao Exportar para o Excel
                        //Session.Session session = Sinacor.Infra.UI.Session.SessionManager.GetInstance().GetCurrentSession();
                        //string user = "";
                        //int companyId = 0;

                        //if (session != null)
                        //{
                        //    user = session.User.LoginName;
                        //    companyId = session.Company.Id;
                        //}

                        //Sinacor.Infra.Common.Logging.Logger.Write(user, Sinacor.Infra.Common.Logging.LogType.Error, "", companyId, "InterfaceLayer", "ExportExcel", ex, "", "Sinacor.Infra.UI.Controls.SinacorDataGrid_Excel: An error occurred while trying to export to excel file.", Sinacor.Infra.Common.Logging.eErrorType.ErroGeral);

                        PSE.Framework.ErrorLogging.LogData logData = Sinacor.Infra.UI.ErrorLogging.ErrorLogger.WriteLog(PSE.Framework.ErrorLogging.LogType.Error, new Exception("An error occurred exporting DataGrid contents to excel file", ex), _extensionData);

                        string message = string.Format((string)ResourceProviderManager.GetResourceProvider().TryGetResource("Infra.UI.Message.ErroExportarExcel"), ex.Message);
                        SinacorMessageBox.ShowError(message, null, logData, Window.GetWindow(this));
                    }

                }

                this.OnExportedExcel(itemsInfo);
            }

            return exportedToExcel;
        }
        #endregion

        #region ExportAllExcel
        /// <summary>
        /// Indica se pode exportar todos os itens para Excel
        /// </summary>
        /// <returns>true se puder exportar para Excel, false se não puder</returns>
        protected bool CanExportAllExcel()
        {
            return /*!this.IsEditing &&*/ (this.Items.Count > 0);
        }

        /// <summary>
        /// Exporta todos os itens para Excel
        /// </summary>
        /// <returns>true se exportou com sucesso, false se a exportação foi cancelada no evento <c>ExportingExcel</c></returns>
        public bool ExportAllExcel()
        {
            if (this.CanExportAllExcel())
            {
                return this.ExportExcel(this.ItemsSource);
            }
            return false;
        }
        #endregion

        #region AllowExportExcel
        private bool AllowExportExcel(Microsoft.Windows.Controls.DataGridColumn column)
        {
            bool canUserExportExcel = false;
            bool? canUserExportExcelValue = null;

            // Verifica se a propriedade foi setada no Xaml
            LocalValueEnumerator locallySetProperties = column.GetLocalValueEnumerator();
            while (locallySetProperties.MoveNext())
            {
                DependencyProperty propertyCanUserExportExcel = (DependencyProperty)locallySetProperties.Current.Property;
                if (propertyCanUserExportExcel == DataGridColumnManager.CanUserExportExcelProperty)
                {
                    if (Convert.ToBoolean(propertyCanUserExportExcel.DefaultMetadata.DefaultValue))
                        canUserExportExcelValue = true;
                    else
                        canUserExportExcelValue = false;
                    break;
                }
            }

            // Caso exista CanUserExportExcel no Xaml - segue o valor que está definido 
            if (canUserExportExcelValue != null)
            {
                if (canUserExportExcelValue.Value)
                    canUserExportExcel = true;
                else
                    canUserExportExcel = false;
            }
            // Caso não exista CanUserExportExcel no Xaml - segue a propriedade Visibility
            else
            {
                if (column.Visibility == Visibility.Visible)
                    canUserExportExcel = true;
                else
                    canUserExportExcel = false;
            }

            return canUserExportExcel;
        }
        #endregion
    }
}
